package com.schema2uml;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.apache.commons.dbutils.DbUtils;

public class DatabaseHelper {
	
	private Connection connection;
	
	private DatabaseMetaData databaseMetaData = null;
	
	private String schema = null;
	
	private Map<Integer, String> jdbcTypes = new HashMap<Integer, String>();
	
	@SuppressWarnings("unused")
	private DatabaseHelper() {}

	public DatabaseHelper(String jdbcDriver, String jdbcConnectionUrl, String jdbcUser,
			String jdbcPassword, String schema) {
		try {
			
			Class.forName(jdbcDriver);
			this.connection = DriverManager.getConnection(jdbcConnectionUrl, jdbcUser, jdbcPassword);
			this.databaseMetaData = connection.getMetaData();
		
			this.schema = schema;
			
			Field[] fields = Types.class.getFields();
			Field field;
			for (int i = 0; i < fields.length; i++) {
				field = fields[i];
				jdbcTypes.put((Integer) field.get(null), field.getName());
			}
			
		} catch (ClassNotFoundException e) {
			throw new RuntimeException("Could not load JDBC driver.", e);
		} catch (SQLException e) {
			throw new RuntimeException(e);
		} catch (IllegalArgumentException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		}
	}

	public ResultSet getTables() throws SQLException {
		return databaseMetaData.getTables(null, this.schema, null, new String[] { "TABLE" });
	}
	
	public ResultSet getColumns(String tableName) throws SQLException {
		return databaseMetaData.getColumns(null, this.schema, tableName, null);
	}
	
	public ResultSet getImportedKeys(String tableName) throws SQLException {
		return databaseMetaData.getImportedKeys(null, this.schema, tableName);
	}

	public Collection<String> getPrimaryKeys(String tableName) throws SQLException {
		Collection<String> result = new HashSet<String>();
		ResultSet resultSet = databaseMetaData.getPrimaryKeys(null, schema, tableName);
		while (resultSet.next()) {
			result.add(resultSet.getString("COLUMN_NAME"));
		}
		DbUtils.closeQuietly(resultSet);
		return result;
	}
	
	public boolean isColumnNullable(String tableName, String columnName) throws SQLException {
		boolean result = true;
		ResultSet resultSet = this.databaseMetaData.getColumns(null, this.schema, tableName, columnName);
		while (resultSet.next()) {
			result = resultSet.getInt("NULLABLE") != DatabaseMetaData.attributeNoNulls;
		}
		DbUtils.closeQuietly(resultSet);
		return result;
	}
	
	public void closeQuitely(){
		DbUtils.closeQuietly(connection);
	}
	
	public String findJdbcType(int jdbcType) {
		return (String) jdbcTypes.get(new Integer(jdbcType));
	}
}
